/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.commons.exception.service;

import io.iec.edp.caf.commons.exception.api.ExceptionHandler;
import io.iec.edp.caf.commons.exception.core.ExceptionUtility;
import io.iec.edp.caf.commons.exception.entity.CafExceptionHandleException;
import io.iec.edp.caf.commons.exception.entity.ExceptionContext;
import io.iec.edp.caf.commons.exception.entity.ExceptionErrorCode;
import io.iec.edp.caf.commons.exception.entity.ExceptionHandlerInfo;
import io.iec.edp.caf.commons.utils.InvokeService;

import java.util.ArrayList;
import java.util.List;

/**
 * handler的程序入口
 *
 * @author Leon Huo
 * @Date: 2021/4/25
 */
public class ExceptionHandlerEntry {
    private ExceptionHandlerEntry() {
    }

    private volatile static ExceptionHandlerEntry current = null;

    //实例化   双检锁实现单例模式
    public static ExceptionHandlerEntry getCurrent() {
        if (current == null) {
            synchronized (ExceptionHandlerEntry.class) {
                if (current == null)
                    current = new ExceptionHandlerEntry();
            }
        }
        return current;
    }


    /**
     * 内置Handler处理-(如果日志、客户端和服务端统一，则只需要这一个即可)
     *
     * @param handlerInfo handler的配置信息
     */
    public Exception excuteDefaultExceptionHandler(ExceptionContext exceptionContext, ExceptionHandlerInfo handlerInfo) {
        List<ExceptionHandlerInfo> handlerInfoList = new ArrayList<>();
        handlerInfoList.add(handlerInfo);
        //获取Handler
        ExceptionHandler iExceptionHandler = this.getExceptionHandlers(exceptionContext, handlerInfoList).get(0);
        return iExceptionHandler.handleException(exceptionContext);
    }


    /**
     * 获取Handler列表
     *
     * @param exceptionContext 异常上下文
     * @param handlerInfoList  Handler的配置信息列表
     * @return
     */
    private List<ExceptionHandler> getExceptionHandlers(ExceptionContext exceptionContext, List<ExceptionHandlerInfo> handlerInfoList) {
        List<ExceptionHandler> exceptionHandler = new ArrayList<>();
        //循环 handlerDatas，创建Handler实例
        for (ExceptionHandlerInfo info : handlerInfoList) {
            exceptionHandler.add(createHandler(info, exceptionContext));
        }
        return exceptionHandler;
    }


    /**
     * 创建Handler的实例
     *
     * @param exceptionHandlerInfo Handler的配置信息
     * @param exceptionContext     异常上下文
     * @return Handler的实例
     */
    private ExceptionHandler createHandler(ExceptionHandlerInfo exceptionHandlerInfo, ExceptionContext exceptionContext) {
        if (exceptionHandlerInfo == null) {
            String message = ExceptionUtility.getExceptionInnerMessage(ExceptionErrorCode.exceptionHandleIsNull);
            throw new CafExceptionHandleException("caf", ExceptionErrorCode.exceptionHandleIsNull, message, exceptionContext.getException());
        }

        // 检查类名称是否已经指定。
        if (exceptionHandlerInfo.getImplClassName() == null || "".equals(exceptionHandlerInfo.getImplClassName())) {
            String message = String.format(ExceptionUtility.getExceptionInnerMessage(ExceptionErrorCode.handleClassIsNull),
                    exceptionHandlerInfo.getName());
            throw new CafExceptionHandleException("caf", ExceptionErrorCode.handleClassIsNull, message, exceptionContext.getException());
        }
        return this.createHandler(exceptionHandlerInfo.getImplClassName());
    }

    /**
     * 创建Handler的实例
     *
     * @param implClassName 实现类名称
     * @return Handler实例
     */
    private ExceptionHandler createHandler(String implClassName) {
        Class<?> clazz = null;
        //获取类
        try {
            //本类为系统级jar包 由默认的LaunchedURLClassLoader加载 此处需传入线程持有的类加载器(CAFClassLoader) 否则implClassName对应的类LaunchedURLClassLoader可能不可见 会抛出ClassNotFoundException
            clazz = InvokeService.getClass(implClassName);
        } catch (Exception e) {
            String message = ExceptionUtility.getExceptionInnerMessage(ExceptionErrorCode.invalidClass);
            throw new CafExceptionHandleException("caf", ExceptionErrorCode.invalidClass, message, e);
        }
        //指定的类必须实现IExceptionHandler接口，没有实现就抛出异常
        if (!ExceptionHandler.class.isAssignableFrom(clazz)) {
            String message = String.format(ExceptionUtility.getExceptionInnerMessage(ExceptionErrorCode.classNotImplInterface), implClassName, "IExceptionHandler");
            throw new CafExceptionHandleException("caf", ExceptionErrorCode.classNotImplInterface, message, null);
        }
        try {
            //创建对象 并返回
            return (ExceptionHandler) clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }
}
